#!/usr/bin/perl

use POSIX qw/strftime/;
use IPC::Run qw(run);
use strict;

sub format_date($) {
    my $iso_date = shift || die "iso_date needed";

    my ($y, $m, $d) = $iso_date =~ /^(\d{4})(\d{2})(\d{2})$/;

    my @dt = (0, 0, 0, $d, $m - 1, $y - 1900, 0, 0, 0);
    my $result = strftime("%e %b %Y", @dt);
    $result =~ s/^\s+//;

    return $result;
}

sub format_date_tbl($) {
    my $iso_date = shift || die "iso_date needed";

    my $date = format_date($iso_date);
    my ($d, $m, $y) = split / /, $date;

    return "$d\\makebox[7ex]{$m}$y";
}

sub get_inv_vars($) {
    my $fh = shift || die "fh needed.";
    my $line;

    my %vars;
    while ($line = <$fh>) {
        chomp($line);
        last if ($line =~ /^Items =/);

        my ($key, $val) = split / = /, $line;
        if ($key =~ /^[A-Za-z]\w*$/) {
            $vars{$key} = $val;
        } else {
            die "Invalid key: $key.";
        }
    }
    my ($item_sep) = $line =~ /^Items = (.)$/;

    # get header captions
    chomp($line = <$fh>);
    my @item_types = split /$item_sep/, $line;
    chomp($line = <$fh>);
    my @item_hdrs = split /$item_sep/, $line;

    my @items;
    while ($line = <$fh>) {
        chomp($line);
        last if ($line eq '');

        my @item_fields = split /$item_sep/, $line;
        push @items, \@item_fields;
    }
    $vars{_item_sep} = $item_sep;
    $vars{_item_types} = \@item_types;
    $vars{_item_hdrs} = \@item_hdrs;
    if ($#item_types != $#item_hdrs) {
        die "Number of item types not equal to " .
            "number of item headers.";
    }
    $vars{_items} = \@items;
    
    if (!defined $vars{Currency} || $vars{Currency} eq '$') {
        $vars{Currency} = '\$';
    }
    if (defined $vars{InvDate}) {
        $vars{InvDate} = format_date($vars{InvDate});
    }

    return \%vars;
}

sub produce_pdf($) {
    my $inv_vars = shift || die "inv_vars needed.";
    my $inv_tpl = $inv_vars->{Tpl};
    my $inv_num = $inv_vars->{InvNum};
    my $currency = $inv_vars->{Currency};
    my $tex_filename = "$inv_num.tex";
    my $pdf_filename = "$inv_num.pdf";

    open TFH, "<$inv_tpl"
        or die "Can't open $inv_tpl for input.";
    open IFH, ">$tex_filename"
        or die "Can't open $tex_filename for output.";

    my $t;
    while ($t = <TFH>) {
        print IFH $t;
        last if ($t =~ /^%% InjoeyBeginParse/);
    }

    while ($t = <TFH>) {
        my $p = q/InjoeyVar{/;
        my $s = q/}/;
            
        my ($key) = $t =~ /\\$p(\w+)$s/;
        if ($key) {
            my $val = $inv_vars->{$key};
            my $find = "$p$key$s";
            my $replace = "$p$val$s";
            $t =~ s/\\$find/\\$replace/g;
        }

        if ($t =~ /%% InjoeyItems/) {
            my @item_types = @{$inv_vars->{_item_types}};
            my @item_hdrs = @{$inv_vars->{_item_hdrs}};
            my $num_of_flds = @item_types;

            my @tbl_specs;
            my %text_flds;
            my %date_flds;
            my %money_flds;
            my $exs = 40;

            for (my $t = 0; $t < $num_of_flds; ++$t) {
                for ($item_types[$t]) {
                    /^(t|text)/ and do {
                        push @tbl_specs, 'p';
                        $text_flds{$t} = 1;
                        last;
                    };
                    /^(d|date)/ and do {
                        push @tbl_specs, 'r';
                        $date_flds{$t} = 1;
                        last;
                    };
                    /^(m|money)/ and do {
                        push @tbl_specs, 'r';
                        $money_flds{$t} = 1;
                        $item_hdrs[$t] = $item_hdrs[$t] .
                                         " ($currency)";
                        last;
                    };
                    push @tbl_specs, 'l';
                }
            }
            my $num_of_text_flds = keys %text_flds;
            $exs /= $num_of_text_flds;
            for (my $t = 0; $t < @tbl_specs; ++$t) {
                if ($tbl_specs[$t] eq 'p') {
                    $tbl_specs[$t] = 'p{' . int($exs) . 'ex}';
                }
            }
            my $tbl_fmt = join ('@{\qquad}', @tbl_specs);

            print IFH <<EOT;
\\begin{center}
\\begin{tabular}{$tbl_fmt}
\\hline
EOT
            print IFH join('&', @item_hdrs);
            print IFH "\\\\\n\\hline\n";

            my %amt_sums;
            my @fld_vals;
            my $f;
            my $item;
            for $item (@{$inv_vars->{_items}}) {
                @fld_vals = @$item;
                last if ($fld_vals[0] =~ /^\*/);

                for $f (keys %date_flds) {
                    $fld_vals[$f] =
                    format_date_tbl($fld_vals[$f]);
                }
                for $f (keys %money_flds) {
                    $amt_sums{$f} += $fld_vals[$f];
                    $fld_vals[$f] =
                    sprintf("%.2f", $fld_vals[$f]);
                }
                print IFH join('&', @fld_vals);
                print IFH "\\\\\n"
            }
            $fld_vals[0] =~ s/^\*//;
            print IFH "\\hline\n";

            # print total line
            for $f (keys %money_flds) {
                @fld_vals[$f] = sprintf("%.2f", $amt_sums{$f});
            }
            print IFH join('&', @fld_vals);
            print IFH "\\\\\n";

            print IFH <<EOT;
\\hline
\\end{tabular}
\\end{center}

EOT
        }

        print IFH $t;
    }

    my @cmd = ('pdflatex', $tex_filename);
    my $result = run \@cmd, undef, undef;

    if (!$result || !(-f $pdf_filename)) {
        return 0;
    }

    return 1;
}

sub main {
    my $inv_num = shift @ARGV;
    if (!defined $inv_num) {
        print "Usage: $0 inv-num\n";
        exit(1);
    }

    my $inv_filename = "$inv_num.inv";
    open IFH, "<$inv_filename"
        or die "Can't open $inv_filename.";
    my $inv_vars = get_inv_vars(\*IFH);

    die if (!produce_pdf($inv_vars));
}

main;
